home *** CD-ROM | disk | FTP | other *** search
/ MACD 5 / MACD 5.bin / workbench / datatypes / marktextdtc014.lha / markabletextdtclass / markabletextdtclass.c < prev    next >
C/C++ Source or Header  |  1997-03-12  |  26KB  |  852 lines

  1.  
  2. /*
  3. **
  4. **  $VER: markabletextdtclass.c 1.4 (12.3.97)
  5. **  markabletextdtclass 1.4
  6. **
  7. **  main file
  8. **
  9. **  (C) Copyright 1996/1997 by Roland 'Gizzy' Mainz
  10. **          All Rights Reserved
  11. **
  12. */
  13.  
  14. /* amiga includes */
  15. #include <exec/types.h>
  16. #include <exec/memory.h>
  17. #include <exec/execbase.h>
  18. #include <exec/alerts.h>
  19. #include <dos/dostags.h>
  20. #include <intuition/icclass.h>
  21. #include <datatypes/datatypesclass.h>
  22. #include <datatypes/textclass.h>
  23.  
  24. /* amiga prototypes */
  25. #include <clib/exec_protos.h>
  26. #include <clib/dos_protos.h>
  27. #include <clib/intuition_protos.h>
  28. #include <clib/datatypes_protos.h>
  29. #include <clib/dtclass_protos.h>
  30. #include <clib/alib_protos.h>
  31.  
  32. /* amiga pragmas */
  33. #include <pragmas/exec_pragmas.h>
  34. #include <pragmas/dos_pragmas.h>
  35. #include <pragmas/intuition_pragmas.h>
  36. #include <pragmas/datatypes_pragmas.h>
  37. #include <pragmas/dtclass_pragmas.h>
  38. #include <pragmas/alib_pragmas.h> /* tagcall stubs */
  39.  
  40. /* ANSI includes */
  41. #include <string.h>
  42.  
  43. /* version string */
  44. #include "markabletextdtclass_rev.h"
  45.  
  46. /* misc defines */
  47. #ifndef NAME
  48. #define NAME "markabletextdtclass"
  49. #endif /* !NAME */
  50.  
  51. /* SASC specific defines */
  52. #define DISPATCHERFLAGS __saveds __asm
  53. #define REGARGS __asm
  54. #define REGA0 register __a0
  55. #define REGA1 register __a1
  56. #define REGA2 register __a2
  57.  
  58. /* version_string */
  59. STRPTR versionstring = VERSTAG;
  60.  
  61. #define V( x )      ((VOID *)(x))
  62. #define G( o )      ((struct Gadget *)(o))
  63. #define EXTG( o )   ((struct ExtGadget *)(o))
  64.  
  65. #define XTAG( expr, tagid ) ((Tag)((expr)?(tagid):(TAG_IGNORE)))
  66.  
  67. long main_retval,
  68.      main_retval2;
  69.  
  70. extern struct ExecBase *SysBase;
  71. extern struct Library  *DOSBase;
  72.  
  73. struct ClassBase
  74. {
  75.     struct ExecBase *cb_SysBase;
  76.     struct Library  *cb_IntuitionBase;
  77.     struct Library  *cb_DataTypesBase;
  78. };
  79.  
  80. /* markabletextdtclass instance data */
  81. struct MarkableTextDTClassInstData
  82. {
  83.     ULONG *mtcid_Methods;     /* If NULL => patch disabled (possibly in directory.datatype,
  84.                                * which includes the same "mark" workaround).
  85.                                */
  86.     BOOL   mtcid_InMarkMode;
  87. };
  88.  
  89.  
  90. const
  91. ULONG markabletextdtclass_includemethods[] =
  92. {
  93.     DTM_SELECT,
  94.     DTM_CLEARSELECTED,
  95.     GM_GOACTIVE,
  96.     GM_HANDLEINPUT,
  97.     GM_GOINACTIVE,
  98.     GM_RENDER,
  99.     OM_NEW,
  100.     OM_DISPOSE,
  101.     OM_UPDATE,
  102.     OM_SET,
  103.     (~0UL)
  104. };
  105.  
  106.  
  107. const
  108. ULONG markabletextdtclass_excludemethods[] =
  109. {
  110.     (~0UL)
  111. };
  112.  
  113. REGARGS  struct IClass *(*OldObtainEngine)( void );
  114.  
  115. /* prototypes */
  116. static REGARGS         struct IClass *NewObtainEngine( void );
  117. static DISPATCHERFLAGS ULONG          Dispatch( REGA0 struct IClass *, REGA2 Object *o, REGA1 Msg );
  118. static                 ULONG         *CopyDTSupportedMethods( struct ClassBase *, Object *, ULONG *, ULONG * );
  119. static                 ULONG          NumMethods( ULONG * );
  120. static                 ULONG         *FindMethod( ULONG *, ULONG );
  121. static                 ULONG          notifyAttrChanges( Object *, struct GadgetInfo *, ULONG, Tag, ... );
  122. static                 BOOL           AttemptRemoveFunction( struct ClassBase *, struct Library *, LONG, APTR, APTR );
  123.  
  124. struct IClass    *MarkableTextDTClass = NULL;
  125. struct ClassBase *cb                  = NULL; /* global context */
  126.  
  127.  
  128. /****** markabletextdtclass/markabletextdtclass ******************************
  129. *
  130. *   NAME
  131. *        markabletextdtclass -- patches text.datatype to support marking
  132. *
  133. *   FORMAT
  134. *        markabletextdtclass
  135. *
  136. *   TEMPLATE
  137. *        ,
  138. *
  139. *   PATH
  140. *        markabletextdtclass:
  141. *
  142. *   PURPOSE
  143. *        This patch allows marking in all text.datatype (ascii, IFF FTXT
  144. *        C/C++-Source etc.)-based objects.
  145. *
  146. *   DESCRIPTION
  147. *        During creation of mpeg#?.datatype (misc datatypes for system/video/
  148. *        audiostreams) and SwitchWindow (object-oriented BOOPSI environment
  149. *        (analyse, create or modify BOOPSI objects including datatypes ones)),
  150. *        I wrote a directory.datatype. Up to version 1.3 I had problems with
  151. *        DTM_COPY/DTM_WRITE. As a part of the fix work I found the BUG
  152. *        causing marking (DTM_SELECT) don't work properly. Later I extracted
  153. *        the code for this and put it into this project.
  154. *
  155. *   KNWON BUGS
  156. *        - HACK
  157. *
  158. *        - not well analysed (possible memory loss etc. (not seen, but
  159. *          possible))
  160. *
  161. *   HISTORY
  162. *        V1.1
  163. *          - First Aminet release
  164. *
  165. *        V1.2
  166. *         - Disables the patch when running in a directory.datatype object
  167. *           (directory.datatype contains the same mark patch, doing the same
  168. *           things twice is not very usefull).
  169. *
  170. *         - Avoids the usage of this patch when a text.datatype > V40 occurs
  171. *           in the system.
  172. *
  173. *        V1.3
  174. *         - Fixed a longstandig bug:
  175. *           Because the text.datatype/ObtainEngine-function wasn't patched,
  176. *           plane text.datatype-Objects didn't include the patch.
  177. *
  178. *           Another effect of this was that other text.datatype-patches can't
  179. *           start (like Stefan Rupperts textdtpatch
  180. *           (Aminet:utl/dtype/TEXTDTPTACH39_2.LhA))
  181. *           (Reported by Timo C. Nentwig (tcn@oxygen.in-berlin.de); Thanks!).
  182. *
  183. *        V1.4
  184. *         - Recompiled with SAS/C 6.57
  185. *
  186. *         - Moved contents of the #?.guide file into this autodoc.
  187. *
  188. *         - The V1.4 release fixes a longstanding bug: The cl_UserData field
  189. *           is used by datatypes.library to store the class library base.
  190. *           Now the cl_UserData is NULL (avoids problems), and the compiler
  191. *           context is accessed in another way.
  192. *
  193. *         - Added a small patch which fixes the buggy scrolling routine
  194. *           when drag-moving (e.g. click on a word, then move mouse
  195. *           out if the text object; the text will scroll in the specified
  196. *           direction) the text.
  197. *
  198. *   NOTE
  199. *
  200. *   INSTALLATION
  201. *        After unpacking this archieve:
  202. *
  203. *        Shell:
  204. *          - Unpack this archieve and copy the markabletextdtclass to
  205. *            SYS:Utilities/
  206. *        Copy CLONE FROM markabletextdtclass TO SYS:Utilities/
  207. *        Put "run <>NIL: markabletextdtclass:markabletextdtclass" in your
  208. *        "S:user-startup".
  209. *
  210. *        make/smake (SAS):
  211. *          - Type 'smake install' in shell
  212. *
  213. *   USAGE
  214. *        Run the programm, it will attect all new object (and subclasses of
  215. *        text.datatype (if they don't redefine the DTA_Methods attribute like
  216. *        directory.datatype does).
  217. *        The programm can be finished with a CTRL_C signal
  218. *        (or Break <CLI_ID> C). It will wait for outstanding object's.
  219. *
  220. *   AUTHOR's REQUEST
  221. *        By  releasing  this program I do  not  place any obligations on you,
  222. *        feel free to share this program with your  friends (and enemies).
  223. *
  224. *        If you want to blame me, report any bugs, or wants a new version
  225. *        send your letter to:
  226. *                        Roland Mainz
  227. *                        Hohenstaufenstraße 8
  228. *                        52388 Nörvenich
  229. *                        GERMANY
  230. *
  231. *        Phone: (+49)(0)2426/901568
  232. *
  233. *        EMAIL is also available:
  234. *        GISBURN@w-specht.rhein-ruhr.de
  235. *
  236. *        If you want to send me attachments larger than 1MB (up to 5MB,
  237. *        more with my permission):
  238. *        Up to March 1997 I'm reachable using this email address, too:
  239. *        Reinhold.A.Mainz@KBV.DE
  240. *
  241. *        | Please put your name and address in your mails !
  242. *        | German mailers should add their phone numbers.
  243. *        | See BUGS section above when submitting bug reports.
  244. *
  245. *        Sorry, but I can only look once a week for mails.
  246. *        If you don't hear something from me within three weeks, please
  247. *        send your mail again (but watch about new releases) (problems with
  248. *        this email port are caused by reconfigurations, hackers, network
  249. *        problems etc.).
  250. *
  251. *        The  entire  "markabletextdtclass"  package may  be  noncommercially
  252. *        redistributed, provided  that  the package  is always  distributed
  253. *        in it's complete  form (including it's documentation).  A small copy
  254. *        fee for media costs is okay but any kind of commercial distribution
  255. *        is strictly forbidden! Comments  and  suggestions  how  to  improve
  256. *        this program  are generally appreciated!
  257. *
  258. *        Thanks to David Junod, who wrote the animation.datatype and the
  259. *        datatypes example code, Matt Dillon for his DICE, and Olaf 'Olsen'
  260. *        Barthel for his help, ideas and some text clips from his
  261. *        documentations.
  262. *
  263. *   SEE ALSO
  264. *       text.datatype, directory.datatype,
  265. *       exec.library/SetFunction
  266. *
  267. *****************************************************************************
  268. *
  269. */
  270.  
  271.  
  272. int main( void )
  273. {
  274.     main_retval2 = 0L;
  275.     main_retval = RETURN_OK;
  276.  
  277.     /* Be sure we've a post-V38-System (DataTypes is only available on post-V38-Systems) */
  278.     if( (SysBase -> LibNode . lib_Version) >= 39UL )
  279.     {
  280.       if( cb = (struct ClassBase *)AllocMem( (ULONG)sizeof( struct ClassBase ), (MEMF_PUBLIC | MEMF_CLEAR) ) )
  281.       {
  282.         cb -> cb_SysBase = SysBase;
  283. #define SysBase (cb -> cb_SysBase)
  284.  
  285.         if( cb -> cb_IntuitionBase = OpenLibrary( "intuition.library", 39UL ) )
  286.         {
  287. #define IntuitionBase (cb -> cb_IntuitionBase)
  288.           if( cb -> cb_DataTypesBase = OpenLibrary( "datatypes.library", 39UL ) )
  289.           {
  290. #define DataTypesBase (cb -> cb_DataTypesBase)
  291.             struct Library *DTClassBase;
  292.  
  293.             if( DTClassBase = OpenLibrary( "datatypes/text.datatype", 39UL ) )
  294.             {
  295.               /* Avoid usage of this tool when using text.datatype > V40 */
  296.               if( (DTClassBase -> lib_Version) <= 40U )
  297.               {
  298.                 struct IClass *TextDTClass;
  299.  
  300.                 /* Obtain text.datatype class ptr */
  301.                 if( TextDTClass = ObtainEngine() )
  302.                 {
  303.                   ClassID oldclassid;
  304.  
  305.                   oldclassid = TextDTClass -> cl_ID;                   /* Save text.datatype's public class name */
  306.                   TextDTClass -> cl_ID = "non_markable_text.datatype"; /* HACK: Replace text.datatype's public class name */
  307.  
  308.                   /* Create our new class... */
  309.                   if( MarkableTextDTClass = MakeClass( TEXTDTCLASS, NULL, TextDTClass, (ULONG)sizeof( struct MarkableTextDTClassInstData ), 0UL ) )
  310.                   {
  311.                     BOOL classvalid    = TRUE, /* Our markable_text.datatype valid ? */
  312.                          ispatched     = TRUE; /* ObtainEngine patch installed ?     */
  313.  
  314.                     /* Prepare class for usage... */
  315.                     MarkableTextDTClass -> cl_Dispatcher . h_Entry = (HOOKFUNC)Dispatch;
  316.                     MarkableTextDTClass -> cl_UserData             = 0UL; /* datatypes.library expects here a (struct Library *) or NULL,
  317.                                                                            * we cannot use this for our context
  318.                                                                            */
  319.  
  320.                     /* Patch text.datatype/ObrainEngine to return our class */
  321.                     OldObtainEngine = (REGARGS struct IClass *(*)( void ))SetFunction( DTClassBase, (-30L), (ULONG (*)())NewObtainEngine );
  322.  
  323.                     /* Make our class public */
  324.                     AddClass( MarkableTextDTClass );
  325.  
  326.                       /* Wait (until user want to quit) */
  327.                       Wait( SIGBREAKF_CTRL_C );
  328.  
  329.                     /* Remove class from public */
  330.                     RemoveClass( MarkableTextDTClass );
  331.  
  332.                     /* Loop until both patched function and our class are freed */
  333.                     do
  334.                     {
  335.                       if( AttemptRemoveFunction( cb, DTClassBase, (-30L), (APTR)OldObtainEngine, (APTR)NewObtainEngine ) )
  336.                       {
  337.                         /* Wait for possible users of the patched function */
  338.                         Delay( (TICKS_PER_SECOND / 2UL) );
  339.  
  340.                         ispatched = FALSE;
  341.                       }
  342.  
  343.                       /* The class can only be freed AFTER our patch has been removed... */
  344.                       if( classvalid && (ispatched == FALSE) )
  345.                       {
  346.                         if( FreeClass( MarkableTextDTClass ) )
  347.                         {
  348.                           MarkableTextDTClass = NULL;
  349.  
  350.                           classvalid = FALSE;
  351.                         }
  352.                       }
  353.                     } while( classvalid || ispatched );
  354.  
  355.                     /* Let other tasks partake (avoids possible race-conditions) */
  356.                     Delay( (TICKS_PER_SECOND / 2UL) );
  357.  
  358.                     /* Done ! */
  359.                   }
  360.                   else
  361.                   {
  362.                     Printf( "can't make new text.datatype class ! (no memory or an other incompatible patch)\n" );
  363.  
  364.                     main_retval2 = ERROR_NO_FREE_STORE;
  365.                     main_retval  = RETURN_FAIL;
  366.                   }
  367.  
  368.                   TextDTClass -> cl_ID = oldclassid;
  369.                 }
  370.                 else
  371.                 {
  372.                   Printf( "can't obtain text.datatype\n" );
  373.  
  374.                   main_retval2 = ERROR_NO_FREE_STORE;
  375.                   main_retval  = RETURN_FAIL;
  376.                 }
  377.               }
  378.               else
  379.               {
  380.                 Printf( "text.datatype > V40 not supported\n" );
  381.  
  382.                 main_retval2 = ERROR_OBJECT_WRONG_TYPE;
  383.                 main_retval  = RETURN_FAIL;
  384.               }
  385.  
  386.               CloseLibrary( DTClassBase );
  387.             }
  388.             else
  389.             {
  390.               Printf( "can't open text.datatype\n" );
  391.  
  392.               main_retval2 = ERROR_NO_FREE_STORE;
  393.               main_retval  = RETURN_FAIL;
  394.             }
  395.  
  396.             CloseLibrary( (cb -> cb_DataTypesBase) );
  397.           }
  398.           else
  399.           {
  400.             Printf( "can't open datatypes.library\n" );
  401.  
  402.             main_retval2 = ERROR_NO_FREE_STORE;
  403.             main_retval  = RETURN_FAIL;
  404.           }
  405.  
  406.           CloseLibrary( (cb -> cb_IntuitionBase) );
  407.         }
  408.         else
  409.         {
  410.           Printf( "can't open intuition.library\n" );
  411.  
  412.           main_retval2 = ERROR_NO_FREE_STORE;
  413.           main_retval  = RETURN_FAIL;
  414.         }
  415.  
  416.         FreeMem( (APTR)cb, (ULONG)sizeof( struct ClassBase ) );
  417.       }
  418.       else
  419.       {
  420.         main_retval2 = ERROR_NO_FREE_STORE;
  421.         main_retval  = RETURN_FAIL;
  422.       }
  423.     }
  424.     else
  425.     {
  426.       main_retval2 = 0L;
  427.       main_retval  = RETURN_FAIL;
  428.     }
  429.  
  430.     PrintFault( main_retval2, NAME );
  431.  
  432.     SetIoErr( main_retval2 );
  433.  
  434.     return( main_retval );
  435. }
  436.  
  437.  
  438. /* text.datatype/ObtainEngine patch */
  439. static
  440. DISPATCHERFLAGS
  441. struct IClass *NewObtainEngine( void )
  442. {
  443.     return( MarkableTextDTClass ); /* Return our new class... */
  444. }
  445.  
  446.  
  447. /* MarkableTextDTClass dispatcher */
  448. static
  449. DISPATCHERFLAGS
  450. ULONG Dispatch( REGA0 struct IClass *cl, REGA2 Object *o, REGA1 Msg msg )
  451. {
  452.     struct MarkableTextDTClassInstData *mtcid;
  453.     ULONG                               retval = 0UL;
  454.  
  455.     switch( msg -> MethodID )
  456.     {
  457.         case OM_NEW:
  458.         {
  459.             if( retval = DoSuperMethodA( cl, o, msg ) )
  460.             {
  461.               ClassID classid = (OCLASS( (Object *)retval ) -> cl_ID);
  462.  
  463.               /* Get a pointer to the object data */
  464.               mtcid = (struct MarkableTextDTClassInstData *)INST_DATA( cl, retval );
  465.  
  466.               /* Check if the we're running inside a "directory.datatype" object
  467.                * TRUE  => disable patch => mtcid -> mtcid_Methods = NULL;
  468.                * FALSE => set up methods table
  469.                */
  470.               if( (classid)?(strcmp( classid, "directory.datatype" )):(1) )
  471.               {
  472.                 /* Create array of supported methods (see OM_GET) */
  473.                 if( !(mtcid -> mtcid_Methods = CopyDTSupportedMethods( cb, (Object *)retval, (ULONG *)markabletextdtclass_includemethods, (ULONG *)markabletextdtclass_excludemethods )) )
  474.                 {
  475.                   /* Can't build DTA_Methods list */
  476.                   CoerceMethod( cl, (Object *)retval, OM_DISPOSE );
  477.                   retval = 0UL;
  478.  
  479.                   SetIoErr( ERROR_NO_FREE_STORE );
  480.                 }
  481.               }
  482.             }
  483.         }
  484.             break;
  485.  
  486.         case OM_DISPOSE:
  487.         {
  488.             mtcid = (struct MarkableTextDTClassInstData *)INST_DATA( cl, o );
  489.  
  490.             /* Free methods array */
  491.             FreeVec( (mtcid -> mtcid_Methods) );
  492.  
  493.             DoSuperMethodA( cl, o, msg );
  494.         }
  495.             break;
  496.  
  497.         case OM_GET:
  498.         {
  499.             mtcid = (struct MarkableTextDTClassInstData *)INST_DATA( cl, o );
  500.  
  501.             /* Redefine DTA_Methods to reflect all supported methods */
  502.             if( ((((struct opGet *)msg) -> opg_AttrID) == DTA_Methods) && (mtcid -> mtcid_Methods) )
  503.             {
  504.               *(((struct opGet *)msg) -> opg_Storage) = (ULONG)(mtcid -> mtcid_Methods);
  505.  
  506.               retval = 1UL;
  507.             }
  508.             else
  509.             {
  510.               retval = DoSuperMethodA( cl, o, msg );
  511.             }
  512.         }
  513.             break;
  514.  
  515.         case OM_UPDATE:
  516.         {
  517.             /* Avoid OM_NOTIFY loops */
  518.             if( DoMethod( o, ICM_CHECKLOOP ) )
  519.             {
  520.               break;
  521.             }
  522.         }
  523.         case OM_SET:
  524.         {
  525.             /* Pass the attributes to the text class and force a refresh
  526.              * if we need it
  527.              */
  528.             if( retval = DoSuperMethodA( cl, o, msg ) )
  529.             {
  530.               /* Top instance ? */
  531.               if( OCLASS( o ) == cl )
  532.               {
  533.                 struct RastPort *rp;
  534.  
  535.                 /* Get a pointer to the rastport */
  536.                 if( rp = ObtainGIRPort( (((struct opSet *)msg) -> ops_GInfo) ) )
  537.                 {
  538.                   struct gpRender gpr;
  539.  
  540.                   /* Force a redraw */
  541.                   gpr . MethodID   = GM_RENDER;
  542.                   gpr . gpr_GInfo  = ((struct opSet *)msg) -> ops_GInfo;
  543.                   gpr . gpr_RPort  = rp;
  544.                   gpr . gpr_Redraw = GREDRAW_UPDATE;
  545.  
  546.                   DoMethodA( o, (Msg)(&gpr) );
  547.  
  548.                   /* Release the temporary rastport */
  549.                   ReleaseGIRPort( rp );
  550.                 }
  551.  
  552.                 retval = 0UL;
  553.               }
  554.             }
  555.         }
  556.             break;
  557.  
  558.         case GM_GOACTIVE:
  559.         case GM_HANDLEINPUT:
  560.         {
  561.             struct DTSpecialInfo *si  = (struct DTSpecialInfo *)(G( o ) -> SpecialInfo);
  562.             struct gpInput       *gpi = (struct gpInput *)msg;
  563.  
  564.             mtcid = (struct MarkableTextDTClassInstData *)INST_DATA( cl, o );
  565.  
  566.             /* Patch enabled ? */
  567.             if( mtcid -> mtcid_Methods )
  568.             {
  569.               /* Check if the user starts marking */
  570.               if( (mtcid -> mtcid_InMarkMode) == FALSE )
  571.               {
  572.                 if( (si -> si_Flags) & DTSIF_DRAGSELECT )
  573.                 {
  574.                   mtcid -> mtcid_InMarkMode = TRUE;
  575.  
  576.                   /* Clear previous marked area */
  577.                   DoMethod( o, DTM_CLEARSELECTED, (gpi -> gpi_GInfo) );
  578.                 }
  579.               }
  580.             }
  581.  
  582.             retval = DoSuperMethodA( cl, o, msg );
  583.         }
  584.             break;
  585.  
  586.         case GM_GOINACTIVE:
  587.         {
  588.             struct gpGoInactive *gpgi = (struct gpGoInactive *)msg;
  589.  
  590.             mtcid = (struct MarkableTextDTClassInstData *)INST_DATA( cl, o );
  591.  
  592.             retval = DoSuperMethodA( cl, o, msg );
  593.  
  594.             /* Patch enabled ? */
  595.             if( mtcid -> mtcid_Methods )
  596.             {
  597.               /* If we were in mark mode... */
  598.               if( mtcid -> mtcid_InMarkMode )
  599.               {
  600.                 struct gpLayout gpl;
  601.  
  602.                 mtcid -> mtcid_InMarkMode = FALSE;
  603.  
  604.                 /* Do size layout (and send DTA_Sync to force a refresh) */
  605.                 gpl . MethodID    = GM_LAYOUT;
  606.                 gpl . gpl_GInfo   = gpgi -> gpgi_GInfo;
  607.                 gpl . gpl_Initial = 0L;
  608.  
  609.                 DoMethodA( o, (Msg)(&gpl) );
  610.  
  611.                 notifyAttrChanges( o, (gpgi -> gpgi_GInfo), 0UL,
  612.                                    GA_ID,    (ULONG)(G( o ) -> GadgetID),
  613.                                    DTA_Sync, 1UL,
  614.                                    TAG_DONE );
  615.               }
  616.             }
  617.         }
  618.             break;
  619.             
  620.         case GM_RENDER:    
  621.         {
  622.             /* Drag-moving patch; scolls ALL bitplanes when moving */
  623.             if( (G( o ) -> Activation) & GACT_ACTIVEGADGET )
  624.             {
  625.               /* Copy msg */
  626.               struct gpRender gpr = *((struct gpRender *)msg);
  627.  
  628.               /* Force a redraw */
  629.               gpr . gpr_Redraw = GREDRAW_REDRAW;
  630.  
  631.               retval = DoSuperMethodA( cl, o, (Msg)(&gpr) );
  632.             }
  633.             else
  634.             {
  635.               retval = DoSuperMethodA( cl, o, msg );
  636.             }
  637.         }
  638.             break;
  639.  
  640.         case DTM_CLEARSELECTED:
  641.         {
  642.             mtcid = (struct MarkableTextDTClassInstData *)INST_DATA( cl, o );
  643.  
  644.             /* Patch enabled ? */
  645.             if( mtcid -> mtcid_Methods )
  646.             {
  647.               struct IBox     *selectdomain;
  648.               struct RastPort *rp;
  649.  
  650.               /* Put my "magic" "nothing selected" value into DTA_SelectDomain and
  651.                * remove the DTSIF_HIGHLIGHT flag
  652.                */
  653.               if( GetAttr( DTA_SelectDomain, o, (ULONG *)(&selectdomain) ) == 1UL )
  654.               {
  655.                 if( selectdomain )
  656.                 {
  657.                   static const struct IBox  all_selected = { ~0, ~0, ~0, ~0 };
  658.  
  659.                   SetAttrs( o, DTA_SelectDomain, (&all_selected), TAG_DONE );
  660.                 }
  661.  
  662.                 ((struct DTSpecialInfo *)(G( o ) -> SpecialInfo)) -> si_Flags &= ~DTSIF_HIGHLIGHT;
  663.               }
  664.  
  665.               /* Get a pointer to the rastport */
  666.               if( rp = ObtainGIRPort( (((struct dtGeneral *)msg) -> dtg_GInfo) ) )
  667.               {
  668.                 struct gpRender gpr;
  669.  
  670.                 /* Force a redraw */
  671.                 gpr . MethodID   = GM_RENDER;
  672.                 gpr . gpr_GInfo  = ((struct dtGeneral *)msg) -> dtg_GInfo;
  673.                 gpr . gpr_RPort  = rp;
  674.                 gpr . gpr_Redraw = GREDRAW_REDRAW;
  675.  
  676.                 DoMethodA( o, (Msg)(&gpr) );
  677.  
  678.                 /* Release the temporary rastport */
  679.                 ReleaseGIRPort( rp );
  680.               }
  681.             }
  682. /* The following statement would only be usefull if we're running on a post-V40 text.datatype
  683.  * Because the startup-code of this patch excludes this, I've disabled the statement below
  684.  */
  685. #ifdef COMMENTED_OUT
  686.             else
  687.             {
  688.               retval = DoSuperMethodA( cl, o, msg );
  689.             }
  690. #endif /* COMMENTED_OUT */
  691.         }
  692.             break;
  693.  
  694.         /* Let the superclass handle everything else */
  695.         default:
  696.         {
  697.             retval = DoSuperMethodA( cl, o, msg );
  698.         }
  699.             break;
  700.     }
  701.  
  702.     return( retval );
  703. }
  704.  
  705.  
  706. /* Create a list of supported methods of this class, including all methods we support (DTA_Methods) */
  707. static
  708. ULONG *CopyDTSupportedMethods( struct ClassBase *cb, Object *o, ULONG *includemethods, ULONG *excludemethods )
  709. {
  710.     if( o )
  711.     {
  712.       ULONG *methods;
  713.  
  714.       if( methods = GetDTMethods( o ) )
  715.       {
  716.         ULONG  numincludemethods,
  717.                nummethods;
  718.  
  719.         ULONG *copymethods;
  720.  
  721.         nummethods        = NumMethods( methods );
  722.         numincludemethods = NumMethods( includemethods );
  723.  
  724.         if( copymethods = (ULONG *)AllocVec( ((nummethods + numincludemethods + 2UL) * sizeof( ULONG )), (MEMF_PUBLIC | MEMF_CLEAR) ) )
  725.         {
  726.           ULONG *x;
  727.  
  728.           /* Copy methods, including their terminator */
  729.           memcpy( (void *)copymethods, (void *)methods, (size_t)((nummethods + 1UL) * sizeof( ULONG )) );
  730.  
  731.           if( includemethods )
  732.           {
  733.             /* Find terminator (== ~0UL) of copymethods */
  734.             if( x = FindMethod( copymethods, (~0UL) ) )
  735.             {
  736.               memcpy( (void *)x, (void *)includemethods, (size_t)((numincludemethods + 1UL) * sizeof( ULONG )) );
  737.             }
  738.           }
  739.  
  740.           if( excludemethods )
  741.           {
  742.             while( (*excludemethods) != (~0UL) )
  743.             {
  744.               if( x = FindMethod( copymethods, (*excludemethods) ) )
  745.               {
  746.                 *x = OM_NEW;
  747.               }
  748.  
  749.               excludemethods++;
  750.             }
  751.           }
  752.  
  753.           return( copymethods );
  754.         }
  755.       }
  756.     }
  757.  
  758.     return( NULL );
  759. }
  760.  
  761.  
  762. static
  763. ULONG NumMethods( ULONG *methods )
  764. {
  765.     ULONG num = 0UL;
  766.  
  767.     if( methods )
  768.     {
  769.       while( (*methods) != (~0UL) )
  770.       {
  771.         methods++;
  772.         num++;
  773.       }
  774.     }
  775.  
  776.     return( num );
  777. }
  778.  
  779.  
  780. static
  781. ULONG *FindMethod( ULONG *methods, ULONG MethodID )
  782. {
  783.     if( methods )
  784.     {
  785.       while( ((*methods) != (~0UL)) && ((*methods) != MethodID) )
  786.       {
  787.         methods++;
  788.       }
  789.  
  790.       if( (*methods) == MethodID )
  791.       {
  792.         return( methods );
  793.       }
  794.     }
  795.  
  796.     return( NULL );
  797. }
  798.  
  799.  
  800. static
  801. ULONG notifyAttrChanges( Object *o, struct GadgetInfo *ginfo, ULONG flags, Tag tag1, ... )
  802. {
  803.     struct opUpdate opu;
  804.  
  805.     opu . MethodID     = OM_NOTIFY;
  806.     opu . opu_AttrList = (struct TagItem *)(&tag1);
  807.     opu . opu_GInfo    = ginfo;
  808.     opu . opu_Flags    = flags;
  809.  
  810.     return( DoMethodA( o, (Msg)(&opu) ) );
  811. }
  812.  
  813.  
  814. static
  815. BOOL AttemptRemoveFunction( struct ClassBase *cb, struct Library *lib, LONG offset, APTR oldfunc, APTR patchfunc )
  816. {
  817.     BOOL removed = FALSE;
  818.  
  819.     if( lib && offset && oldfunc && patchfunc )
  820.     {
  821.       APTR currfunc;
  822.  
  823.       Forbid();
  824.  
  825.         currfunc = (APTR)SetFunction( lib, offset, (ULONG (*)())oldfunc );
  826.  
  827.         /* Does the code returned from SetFunction match our patch code ? */
  828.         if( currfunc == patchfunc )
  829.         {
  830.           removed = TRUE;
  831.         }
  832.         else
  833.         {
  834.           /* No, restore returned code */
  835.           currfunc = (APTR)SetFunction( lib, offset, (ULONG (*)())currfunc );
  836.  
  837.           /* The following expression MUST never be TRUE */
  838.           if( currfunc != oldfunc )
  839.           {
  840.             /* havoc found, crash expected */
  841.             Alert( AN_Unknown + 0x1357 );
  842.           }
  843.         }
  844.  
  845.       Permit();
  846.     }
  847.  
  848.     return( removed );
  849. }
  850.  
  851.  
  852.